
// ChatConferencesServerDlg.cpp : implementation file
//

#include "stdafx.h"
#include "ChatConferencesServer.h"
#include "ChatConferencesServerDlg.h"
#include "Process.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()


// CChatConferencesServerDlg dialog




CChatConferencesServerDlg::CChatConferencesServerDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CChatConferencesServerDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CChatConferencesServerDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CChatConferencesServerDlg, CDialog)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDC_BTN_LISTEN, &CChatConferencesServerDlg::OnBnClickedBtnListen)
	ON_WM_CLOSE()
END_MESSAGE_MAP()


// CChatConferencesServerDlg message handlers

BOOL CChatConferencesServerDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

	sendType = 0;
	pListMessages = (CListBox*) GetDlgItem(IDC_LIST_MESSAGES);
	pListUsers = (CListBox*) GetDlgItem(IDC_LIST_USERS);

	WORD wVersionRequested;
	WSADATA wsaData;
	wVersionRequested=MAKEWORD(2,2);
	//iNumUser = 0;
	//iTotalUser = 30;
	int err=WSAStartup(wVersionRequested,&wsaData);
	if (err!=0)
		MessageBox(_T("Can't initialize socket"));
	//initArraySocket(iTotalUser);
	
	return TRUE;  // return TRUE  unless you set the focus to a control
}
void CChatConferencesServerDlg::initArraySocket(int n)
{
	arrUsersOnline.resize(n);
	for(int i = 0; i < arrUsersOnline.size(); i++)
	{
		//SOCKET temp;
		//arrUsersOnline[i].sockClient = temp;
		arrUsersOnline[i].sUsername = _T("");
	}
}
void CChatConferencesServerDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CChatConferencesServerDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CChatConferencesServerDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

//**********************************************<<
LRESULT CChatConferencesServerDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
	if (message==WM_SOCKET){
		SockMsg(wParam,lParam);
	}
	return CDialog::WindowProc(message, wParam, lParam);
}
void CChatConferencesServerDlg:: SockMsg(WPARAM wParam, LPARAM lParam)
{
	if (WSAGETSELECTERROR(lParam))
    {
		 // Display the error and close the socket
		closesocket(wParam);
    }
	switch(WSAGETSELECTEVENT(lParam))
    {
		case FD_ACCEPT:
			{
				USER usr;
				usr.sockClient = accept(wParam,NULL,NULL);
				arrUsersOnline.push_back(usr);
				break;
			}
		case FD_READ:
			{
				int index = findSocketClient(wParam);
				if(index < 0)return;

				if (!sendType){
					recv(arrUsersOnline[index].sockClient,(char*)&buffLength,sizeof(int),0);
					sendType=1;
				}
				else
				{
					char* buffer=new char[buffLength+1];
					recv(arrUsersOnline[index].sockClient,buffer,buffLength,0);
					buffer[buffLength]='\0';
					sendType=0;
					sReceivedMessage = buffer;
					sReceivedMessage += _T("-");
					char c[10];
					_itoa(index,c,10);
					sReceivedMessage += c;
					delete buffer;
					vector<CString> res = CProcess::parseString(sReceivedMessage, '-');
					choseAction(res);
				}
				break;
			}
		case FD_CLOSE:
			closesocket(wParam);
			break;
	}
}

void CChatConferencesServerDlg::choseAction(std::vector<CString> arrReceivedPackage)
{
	PACKAGE pack = parseMessage(arrReceivedPackage);
	switch(pack.Type)
	{
		case 0://private
			{
				chatPrivate(pack);
				break;
			}
		case 1://room
			{
				chatRoom(pack);
				break;
			}
	}
}

void CChatConferencesServerDlg::chatRoom(PACKAGE pack)
{
	switch (pack.Code)
	{
		case 100: //hello
		{
			break;
		}
		case 101: //Send Username to login
		{
			CString message;
			message = pack.sUsername;
			message += "-1-";
			if(exitstedUser(pack.sUsername))
			{
				message += "202-all:seq-Username Conflict";
			}
			else//Login
			{
				message += "201-all:seq-Login OK";
				arrUsersOnline[pack.Index].sUsername = pack.sUsername;
				//pListMessages->AddString(pack.sUsername + " login");
				AddString(pack.sUsername + _T(" login"));
				pListUsers->AddString(pack.sUsername);
			}
			sendEndToEnd(message,arrUsersOnline[pack.Index].sockClient);
			break;
		}
		case 103: //Send Chat String
		{
			MessageBox (pack.Message);
			createRoomPackage(203,pack.Message, pack.sUsername);
			break;
		}
		case 104: //Logoff
		{
			int i = findUser(pack.sUsername);
			int j = findUserInList(pack.sUsername);
			if(i >=0)
			{
				//pListMessages->AddString(pack.sUsername + _T(" logoff"));
				AddString(pack.sUsername + _T(" logoff"));
				arrUsersOnline.erase(arrUsersOnline.begin() + i);
			}
			if( j >=0)
			{
				pListUsers->DeleteString(j);
			}
			createRoomPackage(204,_T("Logoff"),pack.sUsername);
			break;
		}
		case 105: //Get list users Online
		{
			//pListMessages->AddString(pack.sUsername + _T(": get list users online"));
			AddString(pack.sUsername + _T(": get list users online"));
			int i = findUser(pack.sUsername);
			if( i >= 0)
			{
				CString message = _T("");
				message += pack.sUsername;
				message += "-1-205-all:seq-";
				message += listUsersOnline();
				//pListMessages->AddString(_T("Server->all: send list users online."));
				AddString(_T("Server->all: send list users online."));
				sendEndToEnd(message,arrUsersOnline[i].sockClient);
				createRoomPackage(205,message,pack.sUsername);
			}
			
			break;
		}
	}
}

void CChatConferencesServerDlg::chatPrivate(PACKAGE pack)//server received
{
	switch (pack.Code)
	{
		case 300: //Request for Private Chat include username
		{
			break;
		}
		case 301: //Send Message
		{
			break;
		}
		case 302: //Logoff mode Private Chat
		{
			break;
		}
	}
}

int CChatConferencesServerDlg::createPrivatePackage(int code, CString sUsername)//Server send
{
	CString package = _T("");
	int index = findUser(sUsername);
	if(index == -1)
	{
		return 0;
	}
	switch(code)
	{
		case 400://Send Request Private chat for username
			{

				break;
			}
		case 401://Send Message
			{
				break;
			}
		case 402://Send Logoff message of mode private chat
			{
				break;
			}
	}
	return sendEndToEnd(package, sockClient);
}

int CChatConferencesServerDlg::createRoomPackage(int code, CString message, CString ownerOfMessage)
{
	CString package = _T("");
	switch(code)
	{
		case 200://Hello
			{
				//do nothing
				break;
			}
		case 203://Send Chat Message
			{
				package += ownerOfMessage;
				package += "-1-203-all:seq-";
				package += message;
				//pListMessages->AddString(_T("Server->all: ") + message);
				break;
			}
		case 204://Send Client Logoff
			{
				package += ownerOfMessage;
				package += "-1-204-all:seq-";
				package += message;
				//pListMessages->AddString(_T("Server->all: ") + ownerOfMessage + _T(" ") + message);
				AddString(_T("Server->all: ") + ownerOfMessage + _T(" ") + message);
				break;
			}
		case 205://list user
			{
				package = message;
				break;
			}
		case 299://Server Logoff
			{
				package += _T("server-1-299-all:seq-");
				package += message;
				break;
			}
	}
	int retcode = -1;
	if(package != _T("") && !package.IsEmpty())
		retcode = sendConferencePackage(package, ownerOfMessage);
	return retcode;
}
int CChatConferencesServerDlg::sendEndToEnd(CString s, SOCKET sClient)
{
	int retcode;
	int Len = s.GetLength();
	char* sendBuff=new char[Len+1];
	strncpy(sendBuff,CT2A(s),s.GetLength());
	sendBuff[Len]='\0';
	//Send kich thuoc truoc
	retcode = send(sClient,(char*)&Len,sizeof(Len),0);
	retcode = send(sClient,(char*)sendBuff,Len,0);
	return retcode;
}
bool CChatConferencesServerDlg::exitstedUser(CString sUsername)
{
	if( sUsername.IsEmpty() || sUsername == "")
		return false;
	for(unsigned int i = 0; i < arrUsersOnline.size(); i++)
	{
		if(arrUsersOnline[i].sUsername.Compare(sUsername) == 0)
		{
			return true;
		}
	}
	return false;
}
CString CChatConferencesServerDlg::listUsersOnline()
{
	CString list = _T("");
	CString temp = _T("");
	int n = pListUsers->GetCount();
	for(int i =0 ; i < n; i++)
	{
		pListUsers->GetText(i,temp);
		list += temp;
		if(i < n-1)
			list += _T(";");
	}
	return list;
}
int CChatConferencesServerDlg::findUser(CString sUsername)
{
	for( unsigned int i = 0; i < arrUsersOnline.size(); i++)
	{
		if(arrUsersOnline[i].sUsername.Compare(sUsername) == 0)
		{
			return i;
		}
	}
	return -1;
}
int CChatConferencesServerDlg::findUserInList(CString sUsername)
{
	CString temp = _T("");
	for(int i = 0; i < pListUsers->GetCount(); i++)
	{
		pListUsers->GetText(i, temp);
		if(temp.Compare(sUsername) == 0)
		{
			return i;
		}
	}
	return -1;
}

int CChatConferencesServerDlg::sendConferencePackage(CString package, CString ownerOfMessage)
{
	int retcode = -1;
	for(unsigned int i = 0; i < arrUsersOnline.size();i++)
	{
		if(arrUsersOnline[i].sUsername.Compare(ownerOfMessage) != 0)
		{
			retcode = sendEndToEnd(package,arrUsersOnline[i].sockClient);
		}
	}
	return retcode;
}

void CChatConferencesServerDlg::OnBnClickedBtnListen()
{
	sockServer = socket(AF_INET, SOCK_STREAM, 0);
	serverAdd.sin_family=AF_INET;
	serverAdd.sin_port = htons(PORT);    
	serverAdd.sin_addr.s_addr = htonl(INADDR_ANY);
	bind(sockServer, (SOCKADDR *)&serverAdd, sizeof(serverAdd));
	listen(sockServer,5);
	int err=WSAAsyncSelect(sockServer,m_hWnd,WM_SOCKET,
		FD_READ|FD_ACCEPT|FD_CLOSE);
	if (err)
		MessageBox(_T("Can't call WSAAsyncSelect"));
	GetDlgItem(IDC_BTN_LISTEN)->EnableWindow(false);
}
PACKAGE CChatConferencesServerDlg::parseMessage(vector<CString> arrCode)
{
	// username-type-code-all:seq-msg-index
	PACKAGE res;
	char *temp;
	int index;
	res.sUsername = arrCode[0];
	CProcess::ConvertCStringToChar(arrCode[1],temp);
	res.Type = atoi(temp);
	CProcess::ConvertCStringToChar(arrCode[2], temp);
	res.Code = atoi(temp);
	index = arrCode[3].Find(':');
	res.Destination = arrCode[3].Left(index);
	CProcess::ConvertCStringToChar(arrCode[3].Right(arrCode[2].GetLength() - (index + 1)),temp);
	res.Sequence = atoi(temp);

	res.Message = arrCode[4];
	int length = arrCode.size ();
	for (int idx = 5 ; idx < length -1; ++ idx) {
		res.Message += "-";
		res.Message += arrCode [idx];
	}

	CProcess::ConvertCStringToChar(arrCode[length -1], temp);
	res.Index = atoi(temp);

	return res;
}
int CChatConferencesServerDlg::findSocketClient(WPARAM wparam)
{
	for(unsigned int i = 0; i <= arrUsersOnline.size(); i++)
	{
		if( arrUsersOnline[i].sockClient == wparam)
		{
			return i;
		}
	}
	return -1;
}
void CChatConferencesServerDlg::AddString(CString message)
{
	CTime time = CTime::GetCurrentTime();
	CString timestamp = _T("");
	char c[10];
	_itoa(time.GetYear(),c,10);
	timestamp += "[";
	timestamp += c;
	_itoa(time.GetMonth(),c,10);
	timestamp += "/";
	timestamp += c;
	_itoa(time.GetDay(),c,10);
	timestamp += "/";
	timestamp += c;
	_itoa(time.GetHour(),c,10);
	timestamp += "-";
	timestamp += c;
	_itoa(time.GetMinute(),c,10);
	timestamp += ":";
	timestamp += c;
	_itoa(time.GetSecond(),c,10);
	timestamp += ":";
	timestamp += c;
	timestamp += "]#  ";
	
	pListMessages->AddString(timestamp + message);
}
void CChatConferencesServerDlg::OnClose()
{
	createRoomPackage(299,_T("Server logoff"),_T("Server"));
	arrUsersOnline.clear();
	if (sockClient!=INVALID_SOCKET)
		shutdown(sockClient,SD_BOTH);
	closesocket(sockServer);
	WSACleanup();
	exit(0);
	CDialog::OnClose();
}
//*********************************************>>